﻿using SerialPortHelper.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Masuit;
using Masuit.Tools;
using SerialPortHelper.Helper;
using System.Threading;
using System.IO;


namespace SerialPortHelper
{
    public partial class FormMain : DevExpress.XtraEditors.XtraForm
    {
        //串口开启状态
        private bool _isOpen = false;
        //循环发送信息状态
        private volatile bool _isCycle = false;
        //循环发送消息线程
        Thread CycleSendThread;
        //发送按钮状态
        private volatile bool _isSending = false;
        //日志路径
        private string logFilePath = "";
        public FormMain()
        {
            InitializeComponent();
            InitData();
            InitSaveLog();
        }
        //初始化数据
        private void InitData()
        {
            //设置绑定列表
            //this.comboBoxEditPort.Properties.Items.AddRange(Faker.GetPorts());
            //扫描电脑上自带的串口
            string[] ports = SerialPort.GetPortNames();
            this.comboBoxEditPort.Properties.Items.AddRange(ports);
            this.comboBoxEditBaudRate.Properties.Items.AddRange(Faker.GetBounds());
            this.comboBoxEditParity.Properties.Items.AddRange(Enum.GetValues(typeof(Parity)));
            this.comboBoxEditDataBits.Properties.Items.AddRange(Faker.GetDataBits());
            this.comboBoxEditStopBits.Properties.Items.AddRange(Enum.GetValues(typeof(StopBits)));

            //设置默认的下标
            this.comboBoxEditPort.SelectedIndex = comboBoxEditPort.Properties.Items.Count > 0 ? 0 : -1;
            this.comboBoxEditBaudRate.SelectedIndex = 13;
            this.comboBoxEditParity.SelectedIndex = 0;
            this.comboBoxEditDataBits.SelectedIndex = 0;
            this.comboBoxEditStopBits.SelectedIndex = 1;
        }
        private void InitSaveLog()
        {
            var LogThread = new Thread(() =>
            {
                while (true)
                {
                    if (checkEditRec2File.Checked && !string.IsNullOrEmpty(logFilePath))
                    {
                        File.WriteAllText(logFilePath, memoEditLog.Text);
                    }

                    Thread.Sleep(10000);
                }
            });
            LogThread.Start();
        }

        //打开/关闭串口
        private void simpleButton1_Click(object sender, EventArgs e)
        {
            if (_isOpen == true)
            {
                serialPort?.Close();
                btnOpen.Text = "开启";
                ChangeComboxEnable(true);
                memoEditLog.AppendText("连接关闭".FormatStringLog());
                return;
            }

            serialPort.PortName = comboBoxEditPort.Text;
            serialPort.BaudRate = comboBoxEditBaudRate.Text.ToInt32();
            serialPort.DataBits = comboBoxEditDataBits.Text.ToInt32();

            //停止位和校验位等枚举类型特殊处理
            //stopBits是枚举类型，转换失败默认讲第一个类型None赋值给stopBits
            if (Enum.TryParse(comboBoxEditStopBits.Text, out StopBits stopBits))
            {
                //停止位不是0电平
                if (stopBits != StopBits.None)
                {
                    serialPort.StopBits = stopBits;
                }
            }

            if (Enum.TryParse(comboBoxEditParity.Text, out Parity parity))
            {
                serialPort.Parity = parity;
            }
            //如果不为null，则打开串口
            serialPort?.Open();
            _isOpen = true;
            ChangeComboxEnable(false);
            //扩展方法，直接找到StringExtension 类中的静态方法 FormatStringLog，并且将连接打开作为参数传递
            memoEditLog.AppendText("连接打开".FormatStringLog());
            btnOpen.Text = "关闭";



        }
        //打开/关闭后不能/可以设置串口参数
        public void ChangeComboxEnable(bool enable)
        {
            comboBoxEditPort.Enabled = enable;
            comboBoxEditBaudRate.Enabled = enable;
            comboBoxEditParity.Enabled = enable;
            comboBoxEditDataBits.Enabled = enable;
            comboBoxEditStopBits.Enabled = enable;
        }

        //发送/停止发送后不能/可以设置发送参数

        private void DisableControls(bool enable)
        {
            checkEditSendAscii.Enabled = enable;
            checkEditSendHex.Enabled = enable;
            checkEditCycle.Enabled = enable;
            textEditCycle.Enabled = enable;
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            memoEditLog.Text = "";
        }

        private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //获取可读取字节长度，创建缓存数组，读入缓存数组
            int len = serialPort.BytesToRead;
            byte[] buf = new byte[len];
            serialPort.Read(buf, 0, len);

            //读入数据转string,必须加System.Text
            string data = System.Text.Encoding.UTF8.GetString(buf);
            //Invoke():在拥有此控件的基础窗口句柄的线程上执行指定的委托
            //里面固定传入委托
            Invoke(new Action(() =>
            {
                if (checkEditRecAscii.Checked)
                {
                    memoEditLog.AppendText(data.FormatStringLog());
                }
                else
                {
                    memoEditLog.AppendText(string.Join(" ", buf.Select(b => b.ToString("X2")).ToArray()).FormatStringLog());
                }
            }));
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            string result = memoEditSend.Text;
            //首先判断是否有追加随机数
            if (checkEditRandom.Checked)
            {
                result += new Random().Next(1, 999).ToString();
            }
            if (result.Length <= 0)
            {
                return;
            }
            try
            {
                //勾选循环发送信息
                if (checkEditCycle.Checked)
                {
                    //且正在发送中,中止线程
                    if (_isSending&& _isCycle)
                    {
                        CycleSendThread.Abort();
                        _isCycle = false;
                        _isSending = false;
                        btnSend.Text = "发送";
                        ChangeComboxEnable(true);

                    }
                    else
                    {
                        //实例化循环发送线程
                        CycleSendThread = new Thread(() =>
                        {
                            while (_isCycle)
                            {
                                SendMessage2Port(result);
                                Thread.Sleep(textEditCycle.EditValue.ToString().ToInt32());
                            }
                        });
                        CycleSendThread.Start();
                        _isCycle = true;
                        //禁用发送参数设置
                        ChangeComboxEnable(false);
                        btnSend.Text = "停止发送";
                        _isSending = true;
                    }
                    

                }
                else
                {
                    //未勾选循环发送消息
                    SendMessage2Port(result);
                    //禁用发送参数设置
                    ChangeComboxEnable(false);
                    _isSending = true;
                }

            }
            catch (Exception ex)
            {
                memoEditLog.AppendText(ex.Message.FormatStringLog());
            }
        }
        //ASCII和HEX发送数据
        private void SendMessage2Port(string result)
        {
            Invoke(new Action(() => {
                if (checkEditSendAscii.Checked)
                {
                    memoEditLog.AppendText(result.FormatStringLog());
                    serialPort.Write(result);
                }
                else
                {
                    byte[] sendBytes = TranStrToToHexByte(result);

                    if (sendBytes != null)
                    {
                        memoEditLog.AppendText(string.Join(" ", sendBytes.Select(b => b.ToString("X2")).ToArray()).FormatStringLog());
                        serialPort.Write(sendBytes, 0, sendBytes.Length);
                    }
                }
            }));
        }

        //字符串转16进制
        private byte[] TranStrToToHexByte(string hexString)
        {
            int i;
            hexString = hexString.Replace(" ", "");//清除空格
            if ((hexString.Length % 2) != 0)//奇数个
            {
                byte[] returnBytes = new byte[(hexString.Length + 1) / 2];

                try
                {
                    for (i = 0; i < (hexString.Length - 1) / 2; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16);
                }
                catch
                {
                    memoEditLog.AppendText("含有非16进制字符".FormatStringLog());
                    return null;
                }

                return returnBytes;
            }
            else
            {
                byte[] returnBytes = new byte[(hexString.Length) / 2];
                try
                {
                    for (i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                }
                catch
                {
                    memoEditLog.AppendText("含有非16进制字符".FormatStringLog());
                    return null;
                }
                return returnBytes;
            }
        }
        //以日志形式显示
        private void checkEditRecLog_CheckedChanged(object sender, EventArgs e)
        {
            StringExtension.checkEditRecLog = checkEditRecLog.Checked;
        }

        private void checkEditRec2File_CheckedChanged(object sender, EventArgs e)
        {
            if (checkEditRec2File.Checked)
            {
                // 弹出保存文件对话框
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    logFilePath = saveFileDialog.FileName;
                }
            }
        }
    }
}
